iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Software Development

Datomic,內建事件溯源的資料庫。系列 第 19

先從 Datalog 談起 -- part 14 (subqueries)

  • 分享至 

  • xImage
  •  

上一章,我們談到了 SQL 查詢的窗口函數 (window function) ,它在 Datalog 沒有直接的對應,但是,我們可以利用自訂聚合函數來做出類似的語意。

仔細想想,窗口函數已經是進階的語法了,但是在 SQL-92 的語法裡,還有一種 HAVING 語法,可以對聚合之後的結果做條件篩選,這種語法又要如何在 Datalog 實現呢?

SQL HAVING 來篩選聚合結果

若有個資料庫內含文章 (post) 和標籤 (tag) 的資料,想要用 SQL 查出:「每個標籤在多少文章裡使用,並且挑出使用次數大於等於三次的標籤,將它們加以輸出。」

我們可以用如下的查詢來達成:

SELECT tag, COUNT(post_id) AS tag_usage
FROM post_tag
GROUP BY tag
HAVING COUNT(post_id) >= 3;

Datalog 的版本:使用子查詢 (sub query)

(d/q '[:find ?tag ?n
       :where
       [(datomic.api/q
         (quote [:find ?e (count ?post)
                 :where [?post :post/tag ?e]]) $)
        [[?tag ?n]]]
       [(>= ?n 3)]] (db/db))

該怎麼理解這段程式呢?

  • Day 13 曾經提到過,Datalog 也充許我們使用函數表達式。第一個 :where 子句 [(datomic.api/q ... $) [[?tag ?n]]] 就是函數表達式,它的形式是 [(<fn> <arg1> <arg2> ...) <result-binding>] 。它會把函數運算 (datomic.api/q ...) 算出的結果,綁定到 [[?tag ?n]] 這個變數裡。

  • 由於函數運算使用了子查詢,所以,我們先把子查詢 (sub query) 的部分拉出來解讀。下方的查詢是「找出所有文章與標籤的組合,並且對標籤加以分群後,算出在文章裡出現的次數」。它算出來的結果會是:標籤:出現次數 ,這個結果會被綁定到 [[?tag ?n]] 這個在母查詢可以存取的變數裡。

(d/q '[:find ?e (count ?post)
       :where [?post :post/tag ?e]]
     (db/db))
  • 最後,母查詢再用 [(>= ?n 3)] 這個斷言表達式來做條件篩選,就可以做出等價於 HAVING 語法的效果。
  • 程式碼連結

其它資源

  1. 歡迎訂閱 PruningSuccess 電子報,主要談論軟體開發、資料處理、資料分析等議題。
  2. 歡迎加入 Clojure 社群

上一篇
先從 Datalog 談起 -- part 13 (SQL window function)
下一篇
Pull API
系列文
Datomic,內建事件溯源的資料庫。25
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言